<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>五子棋 - WebSocket测试</title>
  <style>
    :root {
      --primary-color: #3498db;
      --success-color: #2ecc71;
      --error-color: #e74c3c;
      --warning-color: #f39c12;
      --bg-color: #f5f7fa;
      --card-bg: #ffffff;
      --border-color: #e0e0e0;
      --text-color: #333;
      --text-secondary: #666;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background-color: var(--bg-color);
      color: var(--text-color);
      line-height: 1.6;
      padding: 20px;
      max-width: 1200px;
      margin: 0 auto;
    }

    header {
      text-align: center;
      margin-bottom: 30px;
      padding: 20px;
      background-color: var(--card-bg);
      border-radius: 10px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    }

    h1 {
      color: var(--primary-color);
      margin-bottom: 10px;
    }

    .subtitle {
      color: var(--text-secondary);
      font-size: 1.1rem;
    }

    .container {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 20px;
    }

    @media (max-width: 768px) {
      .container {
        grid-template-columns: 1fr;
      }
    }

    .card {
      background-color: var(--card-bg);
      border-radius: 10px;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
      padding: 20px;
      margin-bottom: 20px;
      transition: transform 0.3s ease;
    }

    .card:hover {
      transform: translateY(-5px);
    }

    .card-title {
      display: flex;
      align-items: center;
      margin-bottom: 20px;
      padding-bottom: 10px;
      border-bottom: 1px solid var(--border-color);
    }

    .card-title i {
      margin-right: 10px;
      font-size: 1.2rem;
      color: var(--primary-color);
    }

    .card h2 {
      font-size: 1.4rem;
      color: var(--text-color);
    }

    .form-group {
      margin-bottom: 20px;
    }

    label {
      display: block;
      margin-bottom: 8px;
      font-weight: 500;
      color: var(--text-secondary);
    }

    input, textarea, select {
      width: 100%;
      padding: 12px;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      font-size: 1rem;
      transition: border-color 0.3s;
    }

    input:focus, textarea:focus, select:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
    }

    .btn-group {
      display: flex;
      gap: 10px;
      margin-top: 20px;
    }

    button {
      flex: 1;
      padding: 12px 20px;
      border: none;
      border-radius: 6px;
      font-size: 1rem;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
    }

    .btn-connect {
      background-color: var(--success-color);
      color: white;
    }

    .btn-connect:hover {
      background-color: #27ae60;
    }

    .btn-disconnect {
      background-color: var(--error-color);
      color: white;
    }

    .btn-disconnect:hover {
      background-color: #c0392b;
    }

    .btn-send {
      background-color: var(--primary-color);
      color: white;
    }

    .btn-send:hover {
      background-color: #2980b9;
    }

    .btn-test {
      background-color: var(--warning-color);
      color: white;
    }

    .btn-test:hover {
      background-color: #d35400;
    }

    button:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }

    .status {
      padding: 15px;
      border-radius: 6px;
      margin-top: 20px;
      font-weight: 500;
    }

    .status-connected {
      background-color: rgba(46, 204, 113, 0.1);
      color: var(--success-color);
      border: 1px solid var(--success-color);
    }

    .status-disconnected {
      background-color: rgba(231, 76, 60, 0.1);
      color: var(--error-color);
      border: 1px solid var(--error-color);
    }

    .status-connecting {
      background-color: rgba(52, 152, 219, 0.1);
      color: var(--primary-color);
      border: 1px solid var(--primary-color);
    }

    .messages {
      height: 300px;
      overflow-y: auto;
      background-color: #f9f9f9;
      border: 1px solid var(--border-color);
      border-radius: 6px;
      padding: 15px;
      font-family: monospace;
      font-size: 0.9rem;
      margin-top: 20px;
    }

    .message {
      margin-bottom: 10px;
      padding: 8px 12px;
      border-radius: 4px;
      background-color: white;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    }

    .incoming {
      border-left: 3px solid var(--primary-color);
    }

    .outgoing {
      border-left: 3px solid var(--success-color);
    }

    .error {
      border-left: 3px solid var(--error-color);
    }

    .timestamp {
      font-size: 0.75rem;
      color: var(--text-secondary);
      margin-bottom: 3px;
    }

    .message-content {
      word-break: break-all;
    }

    footer {
      text-align: center;
      margin-top: 30px;
      padding: 20px;
      color: var(--text-secondary);
      font-size: 0.9rem;
    }
  </style>
</head>
<body>
<header>
  <h1>五子棋游戏 WebSocket 测试</h1>
  <p class="subtitle">测试连接、认证和消息收发功能</p>
</header>

<div class="container">
  <!-- 连接设置 -->
  <div class="card">
    <div class="card-title">
      <h2>连接设置</h2>
    </div>

    <div class="form-group">
      <label for="token">JWT Token</label>
      <input type="text" id="token" placeholder="输入JWT Token">
      <small>使用有效的Token进行认证测试</small>
    </div>

    <div class="form-group">
      <label for="endpoint">WebSocket 端点</label>
      <select id="endpoint">
        <option value="/websocket/gobang">/websocket/gobang (SockJS)</option>
        <option value="/websocket/gobang-native">/websocket/gobang-native (纯WebSocket)</option>
      </select>
    </div>

    <div class="btn-group">
      <button id="connectBtn" class="btn-connect">连接</button>
      <button id="disconnectBtn" class="btn-disconnect" disabled>断开</button>
    </div>

    <div id="connectionStatus" class="status status-disconnected">
      当前状态: 未连接
    </div>
  </div>

  <!-- 消息测试 -->
  <div class="card">
    <div class="card-title">
      <h2>消息测试</h2>
    </div>

    <div class="form-group">
      <label for="messageType">消息类型</label>
      <select id="messageType">
        <option value="move">落子消息 (/game/move)</option>
        <option value="heartbeat">心跳响应 (/heartbeat)</option>
      </select>
    </div>

    <div id="messageParams">
      <!-- 动态显示消息参数 -->
      <div class="form-group">
        <label for="roomId">房间ID</label>
        <input type="text" id="roomId" value="room-123">
      </div>

      <div class="form-group">
        <label for="row">行</label>
        <input type="number" id="row" value="5">
      </div>

      <div class="form-group">
        <label for="col">列</label>
        <input type="number" id="col" value="7">
      </div>
    </div>

    <button id="sendBtn" class="btn-send" disabled>发送消息</button>
    <button id="testBtn" class="btn-test" disabled>发送测试消息</button>
  </div>

  <!-- 消息日志 -->
  <div class="card" style="grid-column: span 2;">
    <div class="card-title">
      <h2>消息日志</h2>
    </div>

    <div id="messages" class="messages">
      <!-- 消息将显示在这里 -->
    </div>
  </div>
</div>

<footer>
  <p>© 2023 五子棋游戏 WebSocket 测试工具 | 用于开发和调试目的</p>
</footer>

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.6.1/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script>
  // WebSocket相关变量
  let stompClient = null;
  let socket = null;
  let connected = false;

  // DOM元素
  const connectBtn = document.getElementById('connectBtn');
  const disconnectBtn = document.getElementById('disconnectBtn');
  const sendBtn = document.getElementById('sendBtn');
  const testBtn = document.getElementById('testBtn');
  const connectionStatus = document.getElementById('connectionStatus');
  const messagesContainer = document.getElementById('messages');
  const messageTypeSelect = document.getElementById('messageType');

  // 更新UI状态
  function updateUIState() {
    connectBtn.disabled = connected;
    disconnectBtn.disabled = !connected;
    sendBtn.disabled = !connected;
    testBtn.disabled = !connected;

    if (connected) {
      connectionStatus.textContent = '当前状态: 已连接';
      connectionStatus.className = 'status status-connected';
    } else {
      connectionStatus.textContent = '当前状态: 未连接';
      connectionStatus.className = 'status status-disconnected';
    }
  }

  // 添加消息到日志
  function addMessage(type, content) {
    const now = new Date();
    const timestamp = now.toLocaleTimeString();
    const messageDiv = document.createElement('div');
    messageDiv.className = `message ${type}`;

    messageDiv.innerHTML = `
                <div class="message-content">${content}</div>
            `;

    messagesContainer.appendChild(messageDiv);
    messagesContainer.scrollTop = messagesContainer.scrollHeight;
  }

  // 连接WebSocket
  function connect() {
    const token = document.getElementById('token').value.trim();
    const endpoint = document.getElementById('endpoint').value;

    if (!token) {
      addMessage('error', '错误: 请提供有效的JWT Token');
      return;
    }

    // 更新状态
    connectionStatus.textContent = '当前状态: 连接中...';
    connectionStatus.className = 'status status-connecting';

    // 创建SockJS连接
    const socketUrl = `http://${window.location.host}${endpoint}`;
    socket = new SockJS(socketUrl);

    // 创建STOMP客户端
    stompClient = Stomp.over(socket);

    // 设置认证头
    const headers = {
      Authorization: `Bearer ${token}`
    };

    // 连接
    stompClient.connect(headers,
      function(frame) {
        connected = true;
        updateUIState();
        addMessage('incoming', `连接成功! 服务器: ${frame.headers.server}`);

        // 订阅测试主题
        stompClient.subscribe('/topic/test', function(message) {
          addMessage('incoming', `收到测试消息: ${message.body}`);
        });

        // 订阅错误队列
        stompClient.subscribe('/user/queue/errors', function(message) {
          addMessage('error', `错误消息: ${message.body}`);
        });

        // 订阅游戏相关主题
        stompClient.subscribe('/topic/game', function(message) {
          addMessage('incoming', `游戏消息: ${message.body}`);
        });

        // 订阅服务器队列
        stompClient.subscribe('/user/queue/messages', function(message) {
          addMessage('incoming', `服务器消息: ${message.body}`);
        });

      },
      function(error) {
        connected = false;
        updateUIState();
        addMessage('error', `连接错误: ${error}`);
      }
    );
  }

  // 断开连接
  function disconnect() {
    if (stompClient !== null) {
      stompClient.disconnect(() => {
        connected = false;
        updateUIState();
        addMessage('info', '已断开连接');
      });
    }
  }

  // 发送测试消息
  function sendTestMessage() {
    if (!stompClient || !connected) {
      addMessage('error', '错误: 未连接到WebSocket');
      return;
    }

    const testMessage = {
      content: '这是一个测试消息',
      timestamp: new Date().toISOString()
    };

    stompClient.send("/app/test", {}, JSON.stringify(testMessage));
    addMessage('outgoing', `发送测试消息: ${JSON.stringify(testMessage)}`);
  }

  // 发送游戏消息
  function sendGameMessage() {
    if (!stompClient || !connected) {
      addMessage('error', '错误: 未连接到WebSocket');
      return;
    }

    const messageType = messageTypeSelect.value;
    let destination, payload;

    switch (messageType) {
      case 'move':
        destination = '/app/game/move';
        payload = {
          type: "MAKE_MOVE", // 必需字段
          data: {
            roomId: document.getElementById('roomId').value,
            row: parseInt(document.getElementById('row').value),
            col: parseInt(document.getElementById('col').value)
          }
        };
        break;

      case 'heartbeat':
        destination = '/app/heartbeat';
        payload = {
          type: "HEARTBEAT_RESPONSE", // 必需字段
          data: {
            timestamp: Date.now() // 长整型时间戳
          }
        };
        break;
    }

    stompClient.send(destination, {}, JSON.stringify(payload));
    addMessage('outgoing', `发送消息到 ${destination}: ${JSON.stringify(payload)}`);
  }

  // 根据消息类型更新UI
  function updateMessageParamsUI() {
    const messageType = messageTypeSelect.value;
    const paramsContainer = document.getElementById('messageParams');

    let html = '';

    if (messageType === 'move' || messageType === 'state') {
      html += `
                    <div class="form-group">
                        <label for="roomId">房间ID</label>
                        <input type="text" id="roomId" value="room-123">
                    </div>
                `;
    }

    if (messageType === 'move') {
      html += `
                    <div class="form-group">
                        <label for="row">行</label>
                        <input type="number" id="row" value="5">
                    </div>
                    <div class="form-group">
                        <label for="col">列</label>
                        <input type="number" id="col" value="7">
                    </div>
                `;
    }

    paramsContainer.innerHTML = html;
  }

  // 初始化
  function init() {
    updateUIState();
    updateMessageParamsUI();

    // 事件监听
    connectBtn.addEventListener('click', connect);
    disconnectBtn.addEventListener('click', disconnect);
    sendBtn.addEventListener('click', sendGameMessage);
    testBtn.addEventListener('click', sendTestMessage);
    messageTypeSelect.addEventListener('change', updateMessageParamsUI);

    // 添加欢迎消息
    addMessage('info', 'WebSocket 测试工具已启动。输入Token并连接以开始测试。');
    addMessage('info', '使用说明:');
    addMessage('info', '1. 输入有效的JWT Token');
    addMessage('info', '2. 选择WebSocket端点');
    addMessage('info', '3. 点击"连接"按钮');
    addMessage('info', '4. 发送测试消息或游戏消息');
  }

  // 页面加载完成后初始化
  document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>